#coding:utf8
import time
from decimal import *
import math
import types
from bson.son import SON

#字符串解码
def strdecode(s):
    try :
        return s.decode('utf8')
    except UnicodeDecodeError :
        try :
            return s.decode('gbk')
        except UnicodeDecodeError :
            try :
                return s.decode('gb2312')
            except UnicodeDecodeError :
                try :
                    return s.decode('gb18030')
                except UnicodeDecodeError :
                    try :
                        return s.decode('gbk', 'ignore')
                    except UnicodeDecodeError :
                        try :
                            return s.decode('utf8', 'ignore')
                        except UnicodeDecodeError :
                            return s

    return s

def sql_transform(s) :
    s = s.replace("\\", "\\\\")
    s = s.replace("'", "\\'")
    return s

#datetime转为时间戳
def dateToTimestamp(myDate) :
    t = myDate.timetuple()
    tstamp = time.mktime(t)
    return int(tstamp)

#计算两个点之间的距离
def geo_distance(loc1, loc2) :
    getcontext().prec = 10
    if loc1[0] == loc2[0] and loc1[1] == loc2[1] : return 0
    try :
        lat1 = math.radians(loc1[0])
        lng1 = math.radians(loc1[1])
        lat2 = math.radians(loc2[0])
        lng2 = math.radians(loc2[1])
    except : return -1
    R = 6371
    v = Decimal(math.sin(lat1)) * Decimal(math.sin(lat2)) + Decimal(math.cos(lat1)) * Decimal(math.cos(lat2)) * Decimal(math.cos(lng2-lng1))
    try : d = Decimal(math.acos(v)) * Decimal(R)
    except : d = -1
    return float(d)

#将对象中的字符串属性都统一编码成utf8
def to_encoding(obj, encoding = 'utf8') :
    if type(obj) is types.IntType : return obj
    elif type(obj) is types.StringType or type(obj) is types.UnicodeType : return obj.encode(encoding)
    elif type(obj) is types.ListType : return [to_encoding(o, encoding) for o in obj]
    elif type(obj) is types.DictType : return {to_encoding(k, encoding) : to_encoding(v, encoding) for k, v in obj.iteritems()}
    else : return obj

#############################################################
#功能:根据地理位置获取周边景点                              #
#输入:mongo_db - 数据库连接                                 #
#     lat - float, 纬度                                     #
#     lng - float, 经度                                     #
#     max_dist - float, 最大距离范围                        #
#可选参数:cityid - integer, 城市id                          #
#     cateids - [], poi类型                                 #
#     order_type - 排序类型，默认按距离                     #
#     limit - integer, 获取数量                             #
#     offset - integer, 偏移量                              #
#############################################################
def get_near_pois(mongo_db, lat, lng, max_dist, **kwargs) :
    cityid = kwargs.get("cityid", 0)
    cateids = kwargs.get("cateids", [])
    order_type = kwargs.get("order_type", "dist")
    limit = kwargs.get("limit", 100)
    offset = kwargs.get("offset", 0)
    
    query = {}
    if cityid : query["cityid"] = cityid
    if len(cateids) : query["cateid"] = {"$in":cateids} 
    if order_type == "dist" :
        mongo_result = mongo_db.database.command(SON([("geoNear", "place_poi"), ("near", {"type":"Point", "coordinates":[lng, lat]}), ("spherical", 1), ("maxDistance", max_dist), ("query", query), ("limit", offset + limit)]))
        if mongo_result["ok"] == 1 :
            result_set = mongo_result["results"]
            return {"status":"success", "poi_list":result_set[offset:offset+limit]}
        return {"status":"error"}
    else :
        mongo_result = mongo_db.database.command(SON([("geoNear", "place_poi"), ("near", {"type":"Point", "coordinates":[lng, lat]}), ("spherical", 1), ("maxDistance", max_dist), ("query", query), ("limit", max(offset+limit, 500))]))
        if mongo_result["ok"] == 1 :
            result_set = mongo_result["results"]
            if order_type.startswith("-") : order_type = order_type[1:]; reverse = True
            else : reverse = False
            try : result_set = sorted(result_set, key = lambda x:x["obj"][order_type], reverse = reverse)[offset:offset+limit]
            except Exception, e : return {"status":"error", "msg":"sort error: %s" % str(e)}
            return {"status":"success", "poi_list":result_set}
        return {"status":"error"}
    
    

